import os
import time
import traceback
from selenium import  webdriver
from selenium.webdriver.common.action_chains import ActionChains
from common import logger,config
from common.verify import Verify
from inter.commonKeys import sysKey


class Web:
    """
    封装web自动化函数
    powered by echo
    2020年4月16日
    """

    def __init__(self,writer):
        self.driver = None
        self.writer = writer
        self.row = 0
        self.e = None
        self.verify = None #验证码识别

    def openbrowser(self,br="chrome",ex=""):
        """
        打开浏览器
        :param br:chrome谷歌 firefox火狐 ie ie浏览器
        :param exe: 对应driver的路径 默认在lib目录
        :return:
        """
        try:
            if br is None or br == "chrome" or br == "":
                option = webdriver.ChromeOptions()
                userfile = os.environ["USERPROFILE"] #获取用户文件路径

                option.add_argument("--user-data-dir=%s\\AppData\\Local\\Google\\Chrome\\user data"%userfile)

                if ex == "":
                    ex = "./lib/conf/chromedriver.exe"
                self.driver = webdriver.Chrome(options=option,executable_path=ex)

            elif br == "firefox":
                if ex == "":
                    ex = "./lib/confi/geckodriver.exe"
                opt = webdriver.FirefoxOptions()
                opt.profile = r'%s\AppData\Roaming\Mozilla\Firefox\Profiles\mytest.mytest' % os.environ["USERPROFILE"]
                self.driver = webdriver.Firefox(executable_path=ex,firefox_options=opt)

            elif br == "ie":
                if ex == "":
                    ex = "./lib/conf/IEDriverServer.exe"
                opt = webdriver.IeOptions()
                opt.profile = r'%s\Local\Microsoft\Windows\INetCache' % os.environ["USERPROFILE"]
                self.driver = webdriver.Ie(executable_path=ex,ie_options=opt)

            self.driver.implicitly_wait(10) #添加隐式等待
            self.__writer_excel(True,"打开%s浏览器成功"%br)

            try:
                self.verify = Verify(config.config['username'],
                                     config.config['password'],config.config['soft_id'])
            except Exception as e:
                logger.warn("您暂时不支持验证码识别")

        except Exception as e:
            self.__writer_excel(False,traceback.format_exc())
            logger.exception(e)
            self.writer.save_close()
            exit(-1) #退出运行

    def geturl(self,url):
        """
        打开网址
        :param url:
        :return:
        """
        if self.driver is None:
            self.__writer_excel(False,"浏览器不存在")
            return  False
        try:
            self.driver.get(url)
            self.__writer_excel(True, "访问地址%s成功"%url)
            return True
        except Exception as e:
            logger.exception(e)
            self.__writer_excel(False, "访问地址%s失败"%url)
            return False

    def __find_ele(self,locator):
        """
        通过定位器找到元素
        :param locator: xpath等元素定位方式
        :return:
        """
        try:
            if locator.startswith("id="):
                locator = locator[locator.find('=')+1:]
                ele = self.driver.find_element_by_id(locator)
            elif locator.startswith("xpath="):
                locator = locator[locator.find('=') + 1:]
                ele = self.driver.find_element_by_xpath(locator)
            elif locator.startswith("tagname="):
                locator = locator[locator.find('=') + 1:]
                ele = self.driver.find_element_by_tag_name(locator)
            elif locator.startswith("name="):
                locator = locator[locator.find('=') + 1:]
                ele = self.driver.find_element_by_name(locator)
            elif locator.startswith("linktext="):
                locator = locator[locator.find('=') + 1:]
                ele = self.driver.find_element_by_link_text(locator)
            elif locator.startswith("css="):
                locator = locator[locator.find('=') + 1:]
                ele = self.driver.find_element_by_css_selector(locator)
            elif locator.startswith("class="):
                locator = locator[locator.find('=') + 1:]
                ele = self.driver.find_element_by_class_name(locator)
            elif locator.startswith("partial="):
                locator = locator[locator.find('=') + 1:]
                ele = self.driver.find_element_by_partial_link_text(locator)
            else:
                ele = self.driver.find_element_by_xpath(locator)
        except Exception as e:
            self.e = traceback.format_exc()
            return None

        return ele

    def click(self,locator):
        """
        通过元素定位器找到元素 并且完成点击操作
        :param locator:
        :return:
        """
        ele = self.__find_ele(locator)
        if ele is None:
            self.__writer_excel(False,self.e)
            return  False
        try:
            ele.click()
            self.__writer_excel(True, "点击元素%s成功" % locator)
            return True
        except Exception as e:
            self.__writer_excel(False, traceback.format_exc())
            logger.exception(self.e)
            return False

    def clickhref(self, locator):
        """
        通过定位器找到a标签元素，然后获取到href连接，进行跳转
        主要是处理IE点击失败的情况
        :param locator: 定位器
        :return: 点击成功/失败
        """
        ele = self.__find_ele(locator)
        if ele is None:
            self.__writer_excel(False, self.e)
            return False

        try:
            href = ele.get_attribute('href')
            self.driver.get(href)
            self.__writer_excel(True, "链接点击成功")
            return True
        except Exception as e:
            self.__writer_excel(False, traceback.format_exc())
            return False

    def jsclick(self,locator):
        """
        点击a标签 针对selenium点击不了的情况
        点击a标签触发js事件 javascript:void(0);
        :param locator:
        :return:
        """
        ele = self.__find_ele(locator)
        if ele is None:
            self.__writer_excel(False, self.e)
            return False
        try:
            self.driver.execute_script("$(arguments[0].click())",ele)
            self.__writer_excel(True, "点击链接成功")
            return True
        except Exception as e:
            logger.exception(self.e)
            self.__writer_excel(False, traceback.format_exc())
            return False

    def runjs(self,js):
        """
        点击a标签触发js事件 JavaScript:void(0);
        :param js:
        :return:
        """
        try:
            time.sleep(3)
            self.driver.execute_script(js)
            self.__writer_excel(True, "点击成功")
            return True
        except Exception as e:
            logger.exception(self.e)
            self.__writer_excel(False, traceback.format_exc())
            return False

    def getimg(self,locator,filename=""):
        """
        获取元素截图
        :param locator:
        :param filename:截图保存的名字
        :return:
        """
        ele = self.__find_ele(locator)
        if ele is None:
            self.__writer_excel(False, self.e)
            return  False

        if filename == "":
            filename = "verify"

        try:
            filename = "./lib/verify/" + filename + ".png"
            ele.screenshot(filename)
            self.__writer_excel(True, "截图成功")
            return True
        except Exception as e:
            self.__writer_excel(False, traceback.format_exc())
            logger.exception(self.e)
            return False

    def getverify(self,codetype=""):
        """
        调用超级鹰识别验证码
        :param codetype: 验证码类型 默认1902
        :return:
        """
        if codetype == "":
            codetype = 1902

        try:
            v = self.verify.PostPic(int(codetype)) #获取验证码PostPic
            if v is None:
                v = None
            sysKey.relations["verify"] = v #关联验证码
            self.__writer_excel(True, "破解验证码成功")
            return True
        except Exception as e:
            v = "None"
            sysKey.relations["verify"] = v
            self.__writer_excel(False, traceback.format_exc())
            logger.error(self.e)
            return False

    def input(self,locator,text):
        """
        输入文本
        :param locator:
        :param text:
        :return:
        """
        ele = self.__find_ele(locator)
        if ele is None:
            self.__writer_excel(False,self.e)
            return  False

        try:
            text = self.__get_relations(text)
            ele.send_keys(text)
            self.__writer_excel(True, "输入成功")
            return  True
        except Exception as e:
            logger.error(self.e)
            self.__writer_excel(False,traceback.format_exc())
            return False

    def inputfile(self,locator,text):
        """

        :param locator:
        :param text: 需要输入的文本
        :return:
        """
        ele = self.__find_ele(locator)
        if ele is None:
            self.__writer_excel(False, self.e)
            return False
        try:
            text = sysKey.path +"\\lib\\verify\\" + text #这里是磁盘要绝对路径
            ele.send_keys(text)
            self.__writer_excel(True, "输入成功")
            return True
        except Exception as e:
            logger.error(self.e)
            self.__writer_excel(False, traceback.format_exc())
            return False

    def sleep(self,t):
        """
        固定等待
        :param t:
        :return:
        """
        try:
            time.sleep(int(t))
            self.__writer_excel(True, "等待")
            return True
        except Exception as e:
            self.__writer_excel(False, traceback.format_exc())
            return False

    def quit(self):
        """
        退出浏览器
        :return:
        """
        try:
            self.driver.quit()
            self.__writer_excel(True, "退出浏览器成功")
            return True
        except Exception as e:
            self.__writer_excel(False, traceback.format_exc())
            return False

    def gettext(self,locator,param="text"):
        """
        获取元素文本 并且保存为关联后参数名 parama
        :param locator:
        :param param:
        :return:
        """
        ele = self.__find_ele(locator)
        if ele is None:
            self.__writer_excel(False, self.e)
            return False

        try:
            text = ele.text
            sysKey.relations[param] = text #设置关联字典
            self.__writer_excel(True, "获取文本%s成功"%text)
            return True
        except Exception as  e:
            self.__writer_excel(False, traceback.format_exc())
            return False

    def __get_relations(self,params):
        """
        使用关联结果
        :param params:需要关联的参数
        :return:
        """
        if params is None:
            return None
        else:
            params = str(params)

        for key in sysKey.relations.keys():
            params = params.replace("{"+ key + "}",str(sysKey.relations[key]))
        return params

    def assertcontains(self,expect,actual):
        """
        断言关键字 是否包含预期
        :param expect: 预期
        :param actual: 实际
        :return:
        """
        actual = self.__get_relations(actual)
        expect = self.__get_relations(expect)

        if actual.__contains__(str(expect)):
            self.__writer_excel(True, actual)
            return True
        else:
            self.__writer_excel(False, actual)
            return False

    def switchwindow(self,index=""):
        """
        窗口切换 切换到index个窗口
        :param index: 窗口下标
        :return:
        """
        if index == "":
            index = 0
        try:
            handles = self.driver.window_handles
            self.driver.switch_to.window(handles[int(index)])
            self.__writer_excel(True, "切换窗口成功")
            return True
        except Exception as e:
            self.__writer_excel(False, traceback.format_exc())
            return False

    def intoiframe(self,locator):
        """
        进入locator指定的iframe
        :param locator:
        :return:
        """
        ele = self.__find_ele(locator)
        if ele is None:
            self.__writer_excel(False, self.e)
            return False
        try:
            self.driver.switch_to.frame(ele) #这里真的是难受frame不要写成iframe
            #self.driver.switch_to_iframe(ele)
            self.__writer_excel(True, "切换iframe成功")
            return  True
        except Exception as e:
            logger.error(traceback.format_exc())
            self.__writer_excel(False, traceback.format_exc())
            return False

    def outifrme(self,locator):
        """
        退出iframe
        :param locator:
        :return:
        """
        try:
            self.driver.switch_to.default_content()
            self.__writer_excel(True, "切回主页面成功")
            return True
        except Exception as e:
            self.__writer_excel(False, traceback.format_exc())
            return False

    def hover(self,locator):
        """
        悬停到元素上面
        :param locator:
        :return:
        """
        ele = self.__find_ele(locator)
        if ele is None:
            self.__writer_excel(False,self.e)
        try:
            actions = ActionChains(self.driver)
            actions.move_to_element(ele).perform()
            self.__writer_excel(True,"悬停到元素成功")
            return True

        except Exception as e:
            logger.error(self.e)
            self.__writer_excel(False,traceback.format_exc())
            return False

    def scrolltoend(self):
        """
        把页面直接滑动到底部
        :return:
        """
        js = "window.scrollTo(0, document.body.scrollHeight)"#滑动滚动条到底部
        try:
            self.driver.execute_script(js)
            self.__writer_excel(True, "页面滑动到底部成功")
            return True

        except Exception as e:
            logger.error(self.e)
            self.__writer_excel(False,"页面滑动到底部失败")
            return False

    def scrollto(self,y):
        """
        向下滑动一定的像素
        :param y: 例如y=200 向下滑动200像素
        :return:
        """
        js = "window.scrollTo(0,%s)"%y #向下移动y像素
        try:
            self.driver.execute_script(js)
            self.__writer_excel(True, "页面滑动到底部成功")
            return True

        except Exception as e:
            logger.error(self.e)
            self.__writer_excel(False,"页面滑动到底部失败")
            return False





    def __writer_excel(self,status,msg):
        """
        写入关键字运行结果
        :param status: 运行状态
        :param msg: 实际结果
        :return:
        """
        if status is True:
            self.writer.write(self.row,7,"PASS",3)
        else:
            self.writer.write(self.row,7,"FAIL",2)

        # 有时候实际结果过长，我们就只保存前1024个字符
        msg = str(msg)
        if len(msg) > 32767:
            msg = msg[0:32767]

        self.writer.write(self.row, 8, str(msg))




